#ifndef PROTO_MGR_H
#define PROTO_MGR_H

#include "share/patterns.h"
#include "share/cs_msg.pb.h"
#include "share/json/json-forwards.h"
using namespace cs;

//------------------------------------------------------------------------------------
template<typename ProtoT>
using MapIniterT = std::function<int32_t(ProtoT &proto, const Json::Value &one, bool &insert)>;

template<typename ProtoT>
using ArrIniterT = std::function<int32_t(ProtoT &proto, const Json::Value &one)>;

template<typename ProtoT>
using ProtoMapT = std::map<int32_t, ProtoT>;

template<typename ProtoT>
using ProtoArrT = std::vector<ProtoT>;



//------------------------------------------------------------------------------------
#define PROTO_BEGIN(name) \
        struct tagProto##name {

#define PROTO_END() \
        };

// 1 
PROTO_BEGIN(Pet)
    int32_t id;
    int32_t cardid;           // 宠物图鉴索引
    int32_t character;
    int32_t family;
    int32_t quality;
    int32_t release_reward;
    int32_t stage;
    int32_t def_normalskill_num;
    int32_t max_normalskill_num;
    int32_t attmod;

    int32_t potent_point;   // 第一次变成这个宠物给的潜能点
    int32_t evolve_level;   // 进化需要等级
    int32_t evolve_to;      // 进化需要等级
    int32_t evo_itemid;    // 进化消耗物品id

    int32_t mutate_family;  // 变异成的系别
    int32_t mutate_prob;    // 变异的几率

    int32_t skill[2];
    int32_t skill_set;
    int32_t aptitude[PetAptitudeNum];
    int32_t star_egg_require;	// 升星需要蛋的品质
    int32_t star_exp;			// 消耗此蛋给的星级经验
    int32_t star_skills[3];		// 升级的技能
    int32_t star_init;			// 初始化的星级
PROTO_END()

PROTO_BEGIN(Character)
    int32_t id;
    double factor[4];
    int32_t random;                         // 0不随机 1不在孵化时随机 2任何时候都随机
PROTO_END()

PROTO_BEGIN(SkillSet)
    int32_t id;
    vector<pair<int32_t, int32_t>> item;    // item, prob
PROTO_END()

PROTO_BEGIN(Skill)
    int32_t id;

    int32_t family;                 // 宠物系别要求 -1 无要求，通用技能

    int32_t point;                    // 触发时机
    int32_t prev_skillid;            // 先决技能id
    int32_t prob;                    // 触发概率
    int32_t cast_num;                // 每次战斗触发次数
    int32_t cast_round;              // 释放的回合数

    int32_t caster_hp_pct_low;        // 释放者生命百分比限制 小于等于时触发
    int32_t caster_hp_pct_high;        // 释放者生命百分比限制 大于时触发
    int32_t target_hp_pct_low;        // 目标生命百分比限制 小于等于时触发
    int32_t target_hp_pct_high;        // 目标生命百分比限制 大于时触发

    int32_t caster_attmodid;        // begin end
    int32_t caster_buffid;            // cast
    int32_t caster_act_num_chg;        // cast
    int32_t caster_damage_valueid;    // cast
    int32_t caster_heal_valueid;    // cast
    bool caster_purge;                // cast

    int32_t target_attmodid;        // begin end
    int32_t target_buffid;          // cast
    int32_t target_act_num_chg;     // cast
    int32_t target_damage_valueid;  // cast
    int32_t target_heal_valueid;    // cast
    bool target_purge;              // cast

PROTO_END()

PROTO_BEGIN(Buff)
    int32_t id;

    bool overlap;                    // 是否可叠加
    int8_t round_num;                // 回合数
    int32_t attmodid;                // 属性改变
    bool immunity;                    // 免疫
    bool dizzy;                        // 眩晕
    bool dummy;                        // 封技
    bool frozen;                    // 冰冻

    int8_t effect_point;            // 效果触发时机
    int32_t damage_valueid;            // 伤害值
    int32_t heal_valueid;            // 治疗量
PROTO_END()

PROTO_BEGIN(Sprite)
    int32_t id;

    int32_t quality;                               // 品质
    int32_t skill[SpriteSkillNum];                 // 技能
    int32_t max_skill_level;					   // 最大技能等级
PROTO_END()

PROTO_BEGIN(SpriteQuality)
    int32_t id;

    vector<int32_t> sprite_protos;             // 这个品质的精灵
    int32_t consume_star[StarProtoNum];        // 消耗的星星
    int32_t factor1;                           // 放生收获因数1
    int32_t factor2;                           // 放生收获因数2
PROTO_END()

PROTO_BEGIN(SpriteSkill)
    int32_t id;

    int32_t point;
    bool self;

    int32_t att;
    int32_t init_pct;
    int32_t inc_pct;

    int32_t init_heal;
    int32_t inc_heal;

    int32_t init_damage;
    int32_t inc_damage;
PROTO_END()

PROTO_BEGIN(AttMod)
    int32_t id;
    int32_t att[4];
    int32_t flat[4];
    int32_t pct[4];
PROTO_END()

PROTO_BEGIN(Value)
    int32_t id;
    int32_t who;    // 0caster
    int32_t att;
    int32_t pct;
    bool damage;    // 普通伤害值
PROTO_END()

// 关卡
PROTO_BEGIN(Level)
    int32_t id;

	int32_t taskpage;			  // 需要达到的任务篇章 大于等于这个值
    int32_t level;                // 关卡等级
    int32_t random;                // 随机

    int32_t pet_protoid[PlayerCombatCSlotNum];                    // 宠物原型id
    int32_t pet_def_att[PlayerCombatCSlotNum][EPetAtt_ARRAYSIZE];            // 宠物属性因数
    int32_t pet_skill[PlayerCombatCSlotNum][PetSpecSkillNum];    // 宠物技能

    int32_t sprite_quality;        // 精灵品质
    int32_t sprite_level;		   // 精灵等级

    int32_t reward;
PROTO_END()

PROTO_BEGIN(Item)
    int32_t id;

    int32_t type;
    int32_t misc1;
    int32_t misc2;
    int32_t misc3;
    int32_t overlap;
    int32_t price;
    int32_t buy_consume;
    int32_t use_after;
    int32_t payfee_limit;
PROTO_END()

PROTO_BEGIN(EquipLevel)
    int32_t id;                                    // 套装等级

    vector<int32_t> levelup_consume;               // 升级消耗

    int32_t enhance_base_num;                      // 初始强化次数
    int32_t enhance_max_num;                       // 最大强化次数
    vector<int32_t> enhance_consume;               // 强化消耗

    int32_t star_min_game_money;                   // 最小星数
    int32_t star_max_game_money;                   // 最大星数
    int32_t star_min_money;                        // 最小星数
    int32_t star_max_money;                        // 最大星数
    int32_t star_money_consume;                    // 打星游戏币消耗
    int32_t star_game_money_consume;               // 打星人民币消耗
PROTO_END()

PROTO_BEGIN(Consume)
    int32_t id;

    int32_t money;
    int32_t game_money;
    int32_t honor;
    int32_t pearl;

    int32_t item_proto[ConsumeItemTypeNum];      // 消耗的物品
    int32_t item_num[ConsumeItemTypeNum];
PROTO_END()

PROTO_BEGIN(Reward)
    int32_t id;

    int32_t pet_exp;
    int32_t pet_friprob;
    int32_t money;
    int32_t game_money;
    int32_t honor;

    int32_t one_item_prob[RewardOneItemTypeNum + 1];       // 奖励的物品几率
    int32_t one_item_proto[RewardOneItemTypeNum + 1];      // 奖励的物品几率
    int32_t one_item_num[RewardOneItemTypeNum + 1];        // 奖励的物品几率

    int32_t many_item_prob[RewardManyItemSlotNum][RewardManyItemTypeNum + 1];       // 奖励的物品几率
    int32_t many_item_proto[RewardManyItemSlotNum][RewardManyItemTypeNum + 1];      // 奖励的物品几率
    int32_t many_item_num[RewardManyItemSlotNum][RewardManyItemTypeNum + 1];        // 奖励的物品几率

PROTO_END()


// boss 关卡
PROTO_BEGIN(BossLevel)
    int32_t id;
    int32_t prev_level; // 先决关卡
    int32_t boss[3];    // 三个boss
    int32_t reset_consume;

    int32_t occupation_mins;  // 占领结束需要时间分钟
    int32_t occupation_reward;// 占领奖励
PROTO_END()

// 遭遇
PROTO_BEGIN(Encounter)
    int32_t id;
    int32_t actnum_mod;      // 行动次数改变
    int32_t boss;     		 // boss关卡
    int32_t reward;			 // 奖励
PROTO_END()

// 遭遇物品
PROTO_BEGIN(EncounterItem)
    int32_t id;
    int32_t encounter;        // 作用的遭遇 遭遇表中id/1000
    int32_t init_actnum_mod;  // 探险开始时改变的行动点数
    int32_t actnum_mod;       // 改变的行动点数
    int32_t rate_effect;      // 游戏币获得倍数
    int32_t consume;          // 消耗
PROTO_END()

// 探险
PROTO_BEGIN(Explore)
    int32_t id;
    int32_t prev_bosslevel;      // 先决boss关卡
    int32_t init_actnum;         // 初始行动点数
    int32_t enter_consume;       // 进入消耗
    int32_t gridnum;			 // 格子数量
    int32_t reward;              // 奖励
    vector<pair<int32_t, int32_t>> encounter;            // item, prob
    vector<int32_t> mapcard;     // 地图图鉴
PROTO_END()


// 宠物升级表
PROTO_BEGIN(PetLevel)
    int32_t id;                                          // 等级，从0开始
    int32_t levelup_exp_need;                            // 升级需要经验
    int32_t release_reward[EQuality_ARRAYSIZE];          // 放生获得奖励
PROTO_END()

// 培养消耗表
PROTO_BEGIN(PetRearConsume)
    int32_t id;                           // 资质数，从0开始顺序填
    int32_t money_consume;                // 用人民币消耗
    int32_t game_money_consume;           // 用游戏币消耗
PROTO_END()

// 宠物品质相关
PROTO_BEGIN(PetQuality)
    int32_t id;                        // 品质数，从0开始顺序填
    int32_t qualityup_give_qexp;       // 提升品质时消耗该品质宠物给多少品质经验
    int32_t qualityup_need_qexp;       // 升级到下个品质需要的品质经验
PROTO_END()

// 扭蛋
PROTO_BEGIN(EggRandom)
    int32_t id;                             // 宠物蛋等级0开始
    int32_t item_prob[PetEggLevelEggNum];   // 每等级宠物蛋种类
    int32_t item_proto[PetEggLevelEggNum];  // 每等级宠物蛋种类
    int32_t consume[cs::CEggRandom_ConsumeType_ConsumeType_ARRAYSIZE];                    // 消耗
PROTO_END()

// 勋章
PROTO_BEGIN(Medal)
    int32_t id;                             // 勋章等级0开始连续不空
	int32_t group;                          // 勋章组 用于积分赛
    int32_t maxpower_add;                   // 体力上限加成
    int32_t attmod;		                    // 属性影响
    int32_t task_page;	                    // 需要的任务篇章
PROTO_END();

// 星星
PROTO_BEGIN(Star)
    int32_t id;                             // 星星id
    int32_t next_star_proto[6];             // 下颗星星
    int32_t next_star_prob[6];              // 下颗星星几率
    int32_t next_star_num;                  // 星星数量
    int32_t money_consumeid;                // 人民币消耗
    int32_t gamemoney_consumeid;            // 游戏币消耗
    int32_t anima_gain;                     // 分解获得灵气
PROTO_END()

// 精灵技能
PROTO_BEGIN(SpriteSkillLevel)
    int32_t id;                                       // 精灵技能等级
    int32_t anima_consume[ESpriteQuality_ARRAYSIZE];  // 升级需要灵气
PROTO_END()

// 星级
PROTO_BEGIN(PetStar)
    int32_t id;                 // 宠物星级
	int32_t expreq;				// 升级到下个星级需要的经验
	int32_t rateup;             // 属性升高百分比
PROTO_END()

struct RandItem {
    int32_t protoid;
    int32_t prob;
    int32_t num;
    RandItem(int32_t protoid, int32_t prob, int32_t num)
    :protoid(protoid), prob(prob), num(num){}
};

PROTO_BEGIN(RandSet)
    int32_t id;
    int32_t protoid[200];
    int32_t prob[200];
    int32_t num[200];
    int32_t item_num;
PROTO_END()

PROTO_BEGIN(ComposeStone)
    int32_t id;                 // 消耗强化石的等级
    int32_t next_stone_protoid; // 下个等级的强化石原型
    int32_t money_prob;         // 人民币几率
    int32_t gamemoney_prob;     // 游戏币几率
    int32_t money_consume;      // 使用人民币消耗
    int32_t gamemoney_consume;  // 使用游戏币消耗
PROTO_END()

// 宠物系别
PROTO_BEGIN(PetFamily)
    int32_t id;                        // 宠物系别0开始不空
    int32_t compose_reward_skill_set;  // 技能数集合id
PROTO_END()

// 宠物魔法印记等级
PROTO_BEGIN(MagicLevel)
    int32_t id;                        // 魔法印记等级0开始不空
    int32_t compose_reward_magic_set;  // 合成出来的魔法印记集合
PROTO_END()

// 宠物魔法印记等级
PROTO_BEGIN(ArenaReward)
    int32_t id;                        // 0开始不空
    int32_t min;
    int32_t max;
    int32_t rewardid;
PROTO_END()


// 任务
PROTO_BEGIN(Task)
    int32_t id;     // 任务id
	int32_t page;	// 篇
	int32_t slot;	// 槽
    int32_t type;   // 任务类型
    int32_t misc;   // 参数
    int32_t reward; // 奖励
PROTO_END()

PROTO_BEGIN(Alive)
    int32_t id;
    int32_t type;
    int32_t count;
    int32_t alive_count;
PROTO_END()

PROTO_BEGIN(AliveReward)
    int32_t id;
    int32_t count;
    int32_t reward;
PROTO_END()

PROTO_BEGIN(MoneyGet)
    int32_t id;         // 0开始连续不空
    int32_t consume;    // 消耗
    int32_t gain_min;   // 获得
    int32_t gain_max;   // 获得
PROTO_END()

// 首次充值奖励
PROTO_BEGIN(Charge)
    int32_t id;                      // 填rmb
    int32_t money;                   // 给的游戏币
PROTO_END()

// 累计充值奖励
PROTO_BEGIN(AccChargeReward)
    int32_t id;                       // 0开始不空
    int32_t type;                     // 0为每日1为每周
    int32_t fee;                      // 累计充值rmb
    int32_t rewardid;                 // 奖励
PROTO_END()

// 宠物魔法印记等级
PROTO_BEGIN(WorldBossReward)
	int32_t id;                        // 0开始不空
	int32_t min;
	int32_t max;
	int32_t rewardid;
PROTO_END()

PROTO_BEGIN(TrainReward)
	int32_t id;							// pet level
	int32_t exp;
	int32_t gamemoney;
PROTO_END()

PROTO_BEGIN(Floor)
	int32_t id;							// floor num from 0 no space
	int32_t special_reward;
	int32_t levelid;
	int32_t jump_consume;
PROTO_END()

PROTO_BEGIN(PetFriendStage)
	int32_t id;							// 0 开始不连续

	int32_t req_friendvalue;
	int32_t wash_m_consumeid;
	int32_t wash_g_consumeid;		//
	int32_t feed_consumeid;				// 快速
	int32_t next_consumeid;				// 进阶

	int32_t tran_consumeid;				// 传承进阶

	struct randatt_t {
		int32_t att;					// 0-3 4-7
		int32_t min;
		int32_t max;
	};
	vector<randatt_t> g_randatts;
	vector<randatt_t> m_randatts;
PROTO_END()

PROTO_BEGIN(SpriteFormLevel)
	int32_t id;
	int32_t refresh_consume;
	int32_t levelup_anima;
	int32_t att_num;
	int32_t att_value[15];	// 0-10 11-14
PROTO_END()

PROTO_BEGIN(Pointrank)
	int32_t id;
	vector<tuple<int32_t, int32_t, int32_t>> rewards;
PROTO_END()

PROTO_BEGIN(CardReward)
	int32_t id;
	int32_t num;
	int32_t reward;
PROTO_END()

PROTO_BEGIN(InviteReward)
	int32_t id;			// 0,1,2...63
	int32_t reward;
	int32_t num;		// num >= this value is fit
	int32_t medal;		// medal >= this value is fit
PROTO_END()

PROTO_BEGIN(LuckyStar)
	int32_t id;			// 0,1...
	int32_t itemid;		// 物品id
	int32_t num;		// 数量
	int32_t group;		// 组
PROTO_END()

#undef PROTO_BEGIN
#undef PROTO_END

//------------------------------------------------------------------------------------
class ProtoMgr {
public:

    bool init();
    void destroy();
    bool reload();
    bool check();

    template<typename ProtoT>
    const ProtoT* proto(int32_t id, const ProtoMapT<ProtoT> &map) {
        auto itr = map.find(id);
        if (itr == map.end())
            return NULL;
        return &itr->second;
    }

    template<typename ProtoT>
    const ProtoT* proto(int32_t id, const ProtoArrT<ProtoT> &arr) {
        if (id >= arr.size())
            return NULL;
        return &arr[id];
    }

#define PROTO_MAP(name) \
        ProtoMapT<tagProto##name> _mapProto##name
#define PROTO_ARR(name) \
        ProtoArrT<tagProto##name> _arrProto##name

    // 2
    PROTO_MAP(Pet);
    PROTO_MAP(Character);
    PROTO_MAP(SkillSet);
    PROTO_MAP(Skill);
    PROTO_MAP(Buff);
    PROTO_MAP(Sprite);
    PROTO_MAP(SpriteSkill);
    PROTO_MAP(AttMod);
    PROTO_MAP(Value);
    PROTO_MAP(Level);
    PROTO_MAP(Item);
    PROTO_MAP(Consume);
    PROTO_MAP(Reward);
    PROTO_MAP(BossLevel);
    PROTO_MAP(EncounterItem);
    PROTO_MAP(Encounter);
    PROTO_MAP(Explore);
    PROTO_MAP(RandSet);
    PROTO_MAP(Task);
    PROTO_MAP(Charge);

    PROTO_ARR(EquipLevel);
    PROTO_ARR(PetLevel);
    PROTO_ARR(PetRearConsume);
    PROTO_ARR(PetQuality);
    PROTO_ARR(EggRandom);
    PROTO_ARR(Medal);
    PROTO_ARR(Star);
    PROTO_ARR(SpriteQuality);
    PROTO_ARR(SpriteSkillLevel);
    PROTO_ARR(PetStar);
    PROTO_ARR(ComposeStone);
    PROTO_ARR(PetFamily);
    PROTO_ARR(MagicLevel);
    PROTO_ARR(ArenaReward);
    PROTO_ARR(Alive);
    PROTO_ARR(AliveReward);
    PROTO_ARR(MoneyGet);
    PROTO_ARR(AccChargeReward);
    PROTO_ARR(WorldBossReward);
    PROTO_ARR(TrainReward);
    PROTO_ARR(Floor);
    PROTO_ARR(PetFriendStage);
    PROTO_ARR(SpriteFormLevel);
    PROTO_ARR(Pointrank);
    PROTO_ARR(CardReward);
    PROTO_ARR(InviteReward);
    PROTO_ARR(LuckyStar);


#undef PROTO_MAP
#undef PROTO_ARR
    // misc
    vector<uint32_t> rand_characters;
    vector<uint32_t> rand_characters_hatch;
    map<uint32_t, uint32_t> map_pet_evofrom;
    vector<vector<int32_t>> vec_page_task;
};

#define MAProto(name, id)    g_protomgr->proto((id), g_protomgr->_mapProto##name)
#define ARProto(name, id)   g_protomgr->proto((id), g_protomgr->_arrProto##name)

#endif
